package models;

import play.*;
import play.data.validation.Email;
import play.data.validation.Required;
import play.db.jpa.*;
import play.libs.Codec;
import play.modules.search.*;

import javax.persistence.*;

import java.util.*;

import controllers.*;

@Indexed
@Entity
public class User extends Model {
	
	@Field
	@Email
    @Required
    public String email;
    
    @Required
    public String passwordHash;
    
    @Field
    @Required
    public String name;
    
    @Field
    public String realname;
    
    @ManyToMany(cascade=CascadeType.PERSIST)
    public Set<Course> attendedCourses;
    
    @OneToMany(mappedBy="postedBy", cascade=CascadeType.PERSIST)
    public List<Comment> comments;
    
    @ManyToMany
    public Set<Question> votedFor;
    
    @OneToMany(mappedBy="castedBy", cascade=CascadeType.ALL)
    public Set<Vote> votes;
    
    public Date joinDate;
    
    public boolean isAdmin;
    public boolean isPremium;
    public boolean isExpert;
    
    public String needConfirmation;
    
    //Constructor
    public User(String email, String password, String name) {
        this.email = email;
        this.passwordHash = Codec.hexMD5(password);
        this.name = name;
        this.needConfirmation = Codec.UUID();
        this.isAdmin = false;
        this.isPremium = false;
        this.isExpert = false;
        joinDate = new Date();
        create();
    }
    
    //User-related methods
    
    public static User findByEmail(String email) {
        return find("email", email).first();
    }
    
    public static User findByUsername(String username) {
    	return find("name", username).first();
    }
    
    public boolean checkPassword(String password) {
        return passwordHash.equals(Codec.hexMD5(password));
    }

    public static User findByRegistrationUUID(String uuid) {
        return find("needConfirmation", uuid).first();
    }

    public static List<User> findAll(int page, int pageSize) {
        return User.all().fetch(page, pageSize);
    }

    public static boolean isEmailAvailable(String email) {
        return findByEmail(email) == null;
    }
    
    public static boolean isUsernameAvailable(String username) {
    	return findByUsername(username) == null;
    }
    
    
    //Handle Courses
    
    //Attend a course
    public User attendCourse(Course course) {
    	attendedCourses.add(course);
    	this.save();
    	return this;
    }
    
    //Leave a Course
    public User leaveCourse(Course course) {
    	attendedCourses.remove(course);
    	this.save();
    	return this;
    }
    
    // Handle votes on Questions
    
    //Vote for a question
    public User voteOnQuestion(Question question) {
    	votedFor.add(question);
    	this.save();
    	return this;
    }
    
    //Un-vote a question
    public User unvoteQuestion(Question question) {
    	votedFor.remove(question);
    	this.save();
    	return this;
    }
    
    public boolean hasVotedFor(Question question) {
    	return votedFor.contains(question);
    }
    
    //Total Question count
    public long questionCount() {
    	return Question.count("postedBy = ?", this);
    }
    
    //Total answer count
    public long answerCount() {
    	return Answer.count("postedBy = ?", this);
    }
    
    //Find all Questions
    public List<Question> findAllQuestions() {
    	return Question.find("postedBy = ?", this).fetch();
    }
    
    //Find all Comments
    public List<Comment> findAllComments() {
    	return Comment.find("postedBy = ?", this).fetch();
    }
    
    //Find all Answers
    public List<Answer> findAllAnswers() {
    	return Answer.find("postedBy = ?", this).fetch();
    }
}
